/**
 * 依赖收集器，管理所有观察者（Watcher）
 * 每个响应式属性对应一个Dep实例
 */
class Dep {
  constructor() {
    this.subs = []; // 存储Watcher实例
  }

  /**
   * 添加观察者
   * @param {Watcher} sub - 要添加的观察者实例
   */
  addSub(sub) {
    this.subs.push(sub);
  }

  /**
   * 通知所有观察者更新
   */
  notify() {
    this.subs.forEach(sub => sub.update());
  }
}

/**
 * 观察者类，负责依赖更新
 * 在初始化时会自动收集依赖
 */
class Watcher {
  /**
   * @param {Object} vm - 监听的数据对象
   * @param {string|Function} expOrFn - 监听的属性名或着获取值的函数
   * @param {Function} cb - 数据变化时的回调函数
   */
  constructor(vm, expOrFn, cb) {
    this.vm = vm;
    this.getter = typeof expOrFn === 'function'
      ? expOrFn  // 直接使用函数获取值
      : function() { return vm[expOrFn] }; // 通过属性名获取值
    this.cb = cb;
    this.value = this.get(); // 初始化时收集依赖
  }

  /**
   * 获取当前值并收集依赖
   */
  get() {
    Dep.target = this; // 将当前watcher设置为全局目标
    const value = this.getter.call(this.vm);
    Dep.target = null; // 收集完成后重置
    return value;
  }

  /**
   * 当依赖变更时执行回调
   */
  update() {
    const oldValue = this.value;
    this.value = this.get(); // 获取新值
    this.cb && this.cb.call(this.vm, this.value, oldValue); // 执行回调
  }
}

/**
 * 观察者构造类，递归将对象属性转为响应式
 */
class Observer {
  constructor(value) {
    this.value = value;
    this.walk(value); // 开始劫持对象属性
  }

  /**
   * 遍历对象所有属性，将其转换为响应式
   * @param {Object} obj - 要处理的对象
   */
  walk(obj) {
    Object.keys(obj).forEach(key => {
      defineReactive(obj, key, obj[key]);
    });
  }
}

/**
 * 定义响应式属性
 * @param {Object} obj - 目标对象
 * @param {string} key - 属性名
 * @param {*} val - 初始值
 */
function defineReactive(obj, key, val) {
  const dep = new Dep(); // 为每个属性创建依赖收集器
  
  // 递归观察子属性（实现深层响应）
  if (typeof val === 'object') {
    new Observer(val);
  }

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      // 收集当前活动的watcher作为依赖
      if (Dep.target) {
        dep.addSub(Dep.target);
      }
      return val;
    },
    set: function reactiveSetter(newVal) {
      if (newVal === val) return;
      val = newVal;
      // 新值是对象时递归观察（处理属性赋值对象的情况）
      if (typeof newVal === 'object') {
        new Observer(newVal);
      }
      dep.notify(); // 通知所有依赖更新
    }
  });
}

/**
 * 创建观察者的工厂函数
 * @param {*} value - 要观察的值
 * @returns {Observer|undefined}
 */
function observe(value) {
  if (typeof value !== 'object') return;
  return new Observer(value);
}

/****************** 测试用例 ******************/
// 创建响应式对象
const data = { message: 'Hello', info: { count: 0 } };
observe(data);

new Watcher(data, () => {
  const result =  data.message
  console.log('Message changed:', result);
  return result;
}, (newVal, oldVal) => {
  console.log(`Message updated from "${oldVal}" to "${newVal}"`);
});

new Watcher(data, () => {
  const result =  data.info.count
  console.log('Count changed:', result);
  return result;
}, (newVal, oldVal) => {
  console.log(`Count updated from "${oldVal}" to "${newVal}"`);
});

// 触发更新
data.message = 'Hello World';  // 控制台输出更新日志
data.info.count = 5;           // 触发嵌套属性的更新